package com.lancoo.edu.platform.operation.commons.utils.database;

import com.lancoo.edu.platform.operation.commons.utils.RunCommodeUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;

/**
 * @author zhang.ws
 * @date 2024/1/29 11:14
 * @description mysql导出导入工具类
 */
@Slf4j
public class OceanBaseExportImportUtil {


    /**
     * 组装数据库备份导出命令
     *
     * @return 数据库备份导出命令
     */
    private static String getExportCommand(String mysqlDumpPath, String userName,
                                           String password, String host,
                                           String port, String dbNames) {
        StringBuilder command = new StringBuilder();
        String[] dbNameArray = dbNames.split(",");
        if (dbNameArray.length == 1) {
            command.append(mysqlDumpPath)
                    .append("mysqldump")
                    .append(" -h").append(host)
                    .append(" -P").append(port)
                    .append(" -u").append(userName)
                    .append(" -p").append(password)
                    .append(" --skip-extended-insert")
                    .append(" --databases ")
                    .append(dbNameArray[0]);
        } else {
            command = new StringBuilder(mysqlDumpPath + "mysqldump" +
                    " -h" +
                    host +
                    " -P" +
                    port +
                    " -u" +
                    userName +
                    " -p" + "'" +
                    password + "'" +
                    " --skip-extended-insert" +
                    " --databases ");
            for (String dbName : dbNameArray) {
                command.append(dbName).append(" ");
            }
        }
        return command.toString();
    }

    /**
     * 组装数据库备份导出命令
     *
     * @return 数据库备份导出命令
     */
    private static String getExportCommandV2(String mysqlDumpPath, String userName,
                                             String password, String host,
                                             String port, String dbNames, String filePath) {
        StringBuilder command = new StringBuilder();
        String[] dbNameArray = dbNames.split(",");
        if (dbNameArray.length == 1) {
            command.append(mysqlDumpPath)
                    .append("mysqldump")
                    .append(" -h").append(host)
                    .append(" -P").append(port)
                    .append(" -u").append(userName)
                    .append(" -p").append(password)
                    .append(" --skip-extended-insert")
                    .append(" --databases ")
                    .append(dbNameArray[0])
                    .append(" > ")
                    .append(filePath);
        } else {
            command = new StringBuilder(mysqlDumpPath + "mysqldump" +
                    " -h" +
                    host +
                    " -P" +
                    port +
                    " -u" +
                    userName +
                    " -p" + "'" +
                    password + "'" +
                    " --skip-extended-insert" +
                    " --databases ");
            for (String dbName : dbNameArray) {
                command.append(dbName).append(" ");
            }
            command.append(" > ")
                    .append(filePath);
        }
        return command.toString();
    }

    /**
     * 组装数据库备份导入命令
     *
     * @return 数据库备份导入命令
     */
    private static String getImportCommand(String mysqlDumpPath, String userName,
                                           String password, String host,
                                           String port, String dbName) {
        return "mysql" +
                " -h" +
                host +
                " -P" +
                port +
                " -u" +
                userName +
                " -p" +
                password;
    }

    /**
     * 组装数据库备份导入命令
     *
     * @return 数据库备份导入命令
     */
    private static String[] getImportCommandArray(String mysqlDumpPath, String userName,
                                                  String password, String host,
                                                  String port, String dbName, String filePath) {
        return new String[]{
                "mysql" +
                        " -h" + host +
                        " -P" + port +
                        " -u" + userName +
                        " -p" + password +
                        " " + dbName,
                " source " + filePath,
                " exit"
        };
    }


    /**
     * 导出
     *
     * @param mysqlDumpPath mysql的Dump命令地址
     * @param userName      登录mysql数据库用户名
     * @param password      登录mysql数据库密码
     * @param host          mysql数据库IP
     * @param port          mysql数据库端口
     * @param dbName        要导出的数据库
     * @param fileDir       要导出数据文件所在目录
     * @param fileName      导出文件名称
     * @return 是否成功 true/false
     */
    public static String exportSql(String mysqlDumpPath, String userName, String password, String host, String port, String dbName, String fileDir, String fileName) {
        String command = getExportCommand(mysqlDumpPath, userName, password, host, port, dbName);
        log.info("【数据库备份命令：{}】", command);
        log.info("【数据库导出文件地址：{}{}】", fileDir, fileName);
        File dir = new File(fileDir);
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                throw new RuntimeException("文件夹创建失败");
            }
        }
        Path path = Paths.get(fileDir + fileName);
        try (PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(Files.newOutputStream(path), StandardCharsets.UTF_8))) {
            Process exec = Runtime.getRuntime().exec(command);
            try (InputStreamReader inputStreamReader = new InputStreamReader(exec.getInputStream(), StandardCharsets.UTF_8);
                 BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    printWriter.println(line);
                }
                printWriter.flush();
                if (exec.waitFor() == 0) {
                    log.info("【导出成功】");
                    return fileDir + fileName;
                }
            }
        } catch (Exception e) {
            log.error("【数据库备份失败, errorMsg: {}】", e.getMessage(), e);
            try {
                Files.deleteIfExists(path);
            } catch (Exception exception) {
                log.error("【删除文件失败fileName: {}, errorMsg: {}】", path, exception.getMessage(), exception);
            }
        } finally {
            log.info("【清除资源缓存】");
        }
        return null;
    }

    /**
     * 导出
     *
     * @param mysqlDumpPath mysql的Dump命令地址
     * @param userName      登录mysql数据库用户名
     * @param password      登录mysql数据库密码
     * @param host          mysql数据库IP
     * @param port          mysql数据库端口
     * @param dbName        要导出的数据库
     * @param fileDir       要导出数据文件所在目录
     * @param fileName      导出文件名称
     * @return 是否成功 true/false
     */
    public static String exportSqlV2(String mysqlDumpPath, String userName, String password, String host, String port, String dbName, String fileDir, String fileName) {
        File dir = new File(fileDir);
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                throw new RuntimeException("文件夹创建失败");
            }
        }
        Path path = Paths.get(fileDir + fileName);
        String command = getExportCommandV2(mysqlDumpPath, userName, password, host, port, dbName, fileDir + fileName);
        log.info("【数据库备份命令：{}】", command);
        log.info("【数据库导出文件地址：{}{}】", fileDir, fileName);
        try {
            boolean run = RunCommodeUtil.run(command);
            if (run) {
                return fileDir + fileName;
            }
        } catch (Exception e) {
            log.error("【数据库备份失败, errorMsg: {}】", e.getMessage(), e);
            try {
                Files.deleteIfExists(path);
            } catch (Exception exception) {
                log.error("【删除文件失败fileName: {}, errorMsg: {}】", path, exception.getMessage(), exception);
            }
        } finally {
            log.info("【清除资源缓存】");
        }
        return null;
    }


    /**
     * 导入
     *
     * @param mysqlDumpPath mysql的Dump命令地址
     * @param userName      登录mysql数据库用户名
     * @param password      登录mysql数据库密码
     * @param host          mysql数据库IP
     * @param port          mysql数据库端口
     * @param dbName        要导入的数据库
     * @param fileDir       导入文件夹
     * @return 是否成功 true/false
     */
    public static boolean importSqlV2(String mysqlDumpPath, String userName, String password, String host, String port, String dbName, String fileDir) {
        String[] importCommandArray = getImportCommandArray(mysqlDumpPath, userName, password, host, port, dbName, fileDir);
        log.info("【数据库导入命令：{}】", Arrays.toString(importCommandArray));
        log.info("【数据库导入地址文件夹：{}】", fileDir);
        try {
            Process process = Runtime.getRuntime().exec(importCommandArray[0]);
            //执行了第一条命令以后已经登录到mysql了，所以之后就是利用mysql的命令窗口
            //进程执行后面的代码
            try (OutputStreamWriter writer = new OutputStreamWriter(process.getOutputStream())) {
                // 导入命令
                writer.write(importCommandArray[1]);
                writer.flush();
            }
            if (process.waitFor() == 0) {
                log.info("【导入成功】");
                return true;
            }
        } catch (Exception e) {
            log.info("【导入失败】", e);
        }
        log.info("【导入失败】");
        return false;
    }
}
